package com.kaibes.core.base.reflection;

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.util.ArrayList;

public class ClassParserBeans {
    
    public static ClassReflection getClassReflectionInject(Class<?> clazz) {
        return getClassReflection(clazz, true);
    }
    
    public static ClassReflection getClassReflection(Class<?> clazz) {
        return getClassReflection(clazz, false);
    }
    
    public static ClassReflection getClassReflection(Class<?> clazz, boolean isInjected) {
        ClassReflection reflection = new ClassReflection(clazz);
        InjectClass annotation = clazz.getAnnotation(InjectClass.class);
        String name = clazz.getName();
        if (annotation != null) {
            name = annotation.value();
        }
        reflection.setName(name);
        ArrayList<Field> fieldsList = ClassHelper.getAllFields(clazz);
        PropertyDescriptor propertyDescriptor;
        StringBuilder nameBuilder = new StringBuilder();
        ArrayList<String> fieldNameList = new ArrayList<>();
        StringBuilder allNameBuilder = new StringBuilder();
        String[] allFieldNameArr = new String[fieldsList.size()];
        int i = 0;
        if (isInjected) {
            String injectName;
            for (Field field : fieldsList) {
                try {
                    if (field.getAnnotation(NotReflection.class) == null) {
                        name = field.getName();
                        InjectField injectField = field.getAnnotation(InjectField.class);
                        if (injectField != null) {
                            injectName = injectField.value();
                        } else {
                            injectName = name;
                        }
                        propertyDescriptor = new PropertyDescriptor(name, clazz);
                        
                        if (field.getAnnotation(IgnoreName.class) == null) {
                            nameBuilder.append(injectName).append(",");
                            fieldNameList.add(injectName);
                        }
                        allNameBuilder.append(injectName).append(",");
                        allFieldNameArr[i++] = injectName;
                        reflection.getFieldMap().put(injectName, field);
                        reflection.getGetMethodMap().put(injectName, propertyDescriptor.getReadMethod());
                        reflection.getSetMethodMap().put(injectName, propertyDescriptor.getWriteMethod());
                    }
                } catch (IntrospectionException e) {
                    e.printStackTrace();
                }
            }
        } else {
            for (Field field : fieldsList) {
                name = field.getName();
                try {
                    if (field.getAnnotation(NotReflection.class) == null) {
                        propertyDescriptor = new PropertyDescriptor(name, clazz);
                        
                        if (field.getAnnotation(IgnoreName.class) == null) {
                            nameBuilder.append(name).append(",");
                            fieldNameList.add(name);
                        }
                        allNameBuilder.append(name).append(",");
                        allFieldNameArr[i++] = name;
                        reflection.getFieldMap().put(name, field);
                        reflection.getGetMethodMap().put(name, propertyDescriptor.getReadMethod());
                        reflection.getSetMethodMap().put(name, propertyDescriptor.getWriteMethod());
                    }
                } catch (IntrospectionException e) {
                    e.printStackTrace();
                }
            }
        }
        String[] fieldNameArr = new String[fieldNameList.size()];
        fieldNameList.toArray(fieldNameArr);
        nameBuilder.deleteCharAt(nameBuilder.length() - 1);
        allNameBuilder.deleteCharAt(allNameBuilder.length() - 1);
        reflection.setAllFieldNameArr(allFieldNameArr);
        reflection.setAllFieldNameString(allNameBuilder.toString());
        reflection.setFieldNameArr(fieldNameArr);
        reflection.setFieldNameString(nameBuilder.toString());
        return reflection;
    }
    
    public static ArrayList<Field> getFields(Class<? extends Object> clazz) {
        ArrayList<Field> fields = new ArrayList<>();
        BeanInfo beanInfo;
        try {
            beanInfo = Introspector.getBeanInfo(clazz);
            PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
            try {
                Field field;
                for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
                    field = clazz.getDeclaredField(propertyDescriptor.getName());
                    if (field.getAnnotation(NotReflection.class) == null) {
                        fields.add(field);
                    }
                }
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            } catch (SecurityException e) {
                e.printStackTrace();
            }
        } catch (IntrospectionException e) {
            e.printStackTrace();
        }
        return fields;
    }
    
}
